import _ from 'lodash'
import pathToRegexp from 'path-to-regexp'
import React, { Component, ReactNode } from 'react'
import { RouteComponentProps } from 'react-router'
import { Menu, Icon } from 'antd'
import SubMenu from 'antd/lib/menu/SubMenu'
import { ClickParam } from 'antd/lib/menu'
import { IMenuItem, IMenuExtraPath } from '../../types'
import { routeUtils } from '../..'

/**
 * 菜单
 */
class UdMenu extends Component<IUdMenuProps, IUdMenuState> {

  constructor(props: IUdMenuProps) {
    super(props)
    this.state = {
      openKeys: [],
      selectedKeys: [],
      menuNodes: []
    }
  }

  public componentDidMount() {
    this.setState({ menuNodes: this.buildMenu(this.props.menus) })
    this.handleOpenAndSelected(this.props.location.pathname)
  }

  public componentWillReceiveProps(nextProps: IUdMenuProps) {
    if (this.props.location != nextProps.location) {
      console.log(nextProps.location.pathname)
      this.handleOpenAndSelected(nextProps.location.pathname)
    }
  }

  public render() {
    return (
      <div className="ud-menu">
        <Menu inlineIndent={10} theme="light" mode="inline"
          onClick={this.menuClick} onOpenChange={this.menuOpenChange} openKeys={this.state.openKeys} selectedKeys={this.state.selectedKeys}>
          {this.state.menuNodes}
        </Menu>
      </div>
    )
  }

  protected menuOpenChange = (openKeys: string[]) => {
    this.setState({ openKeys: openKeys })
  }

  protected menuClick = (e: ClickParam) => {
    let menu = this.findMenuByKey(e.key)
    if (this.props.onMenuItemClick) {
      this.props.onMenuItemClick(menu)
    } else {
      if (menu && menu.path) {
        let path = menu.path
        if (this.props.extraPaths && this.props.extraPaths[e.key]) {
          path = this.props.extraPaths[e.key](path)
        }
        this.props.history.push(path)
      }
    }
  }

  private buildMenu = (items: IMenuItem[]) => {
    if (!_.isArray(items) || items.length == 0) {
      return null
    }
    let nodes = []
    for (const item of items) {
      if (item.children && item.children.length > 0) {
        nodes.push(
          <SubMenu key={item.key} title={this.buildMenuTitle(item)}>
            {
              this.buildMenu(item.children)
            }
          </SubMenu>
        )
      } else {
        nodes.push(<Menu.Item key={item.key}>{this.buildMenuTitle(item)}</Menu.Item>)
      }
    }
    return nodes
  }

  private buildMenuTitle = (menu: IMenuItem): ReactNode => {
    let icon = menu.icon
    if (menu.icon) {
      if (_.isString(menu.icon)) {
        icon = <Icon type={menu.icon} />
      }
    } else {
      icon = <Icon />
    }
    return <React.Fragment>{icon}<span className="name">{menu.text}</span></React.Fragment>
  }

  private findMenuByKey = (key: string): IMenuItem | null => {
    let result: IMenuItem | null = null
    const recursion = (items: IMenuItem[]) => {
      for (const item of items) {
        if (item.key == key) {
          result = item
        }
        if (result == null && item.children) {
          recursion(item.children)
        }
      }
    }
    recursion(this.props.menus)
    return result
  }

  private handleOpenAndSelected(path: string) {
    let opens: string[] = []
    let selecteds: string[] = []
    let pathObj = routeUtils.parsePath(path)
    const match = (item: IMenuItem) => {

      let matchInner = (relevants) => {
        for (let i = 0; i < relevants.length; i++) {
          let regex = pathToRegexp(relevants[i])
          if (pathObj.path.match(regex)) {
            return true
          }
        }
        return null
      }

      if (_.isArray(item.relevantPaths) && item.relevantPaths.length > 0) {
        if (matchInner(item.relevantPaths)) {
          return true
        }
      }
      if (this.props.relevants && this.props.relevants[item.key]) {
        if (matchInner(this.props.relevants[item.key])) {
          return true
        }
      }
      if (item.path && item.path === path) {
        return true
      }
      return false
    }

    const recursion = (items: IMenuItem[], parents: string[]) => {
      for (const item of items) {
        if (match(item)) {
          selecteds.push(item.key)
          opens = opens.concat(parents)
        }
        if (item.children) {
          parents.push(item.key)
          recursion(item.children, parents)
          parents.pop()
        }
      }
    }

    recursion(this.props.menus, [])

    this.setState({ openKeys: opens, selectedKeys: selecteds })
  }

}

interface IUdMenuProps extends RouteComponentProps {
  /** 
   * 菜单集合
   */
  menus: IMenuItem[]

  /**
   * 点击菜单项事件
   * 可通过此参数来自定义点击后的跳转逻辑
   */
  onMenuItemClick?: (item: IMenuItem) => void
  /**
   * 菜单和路由的额外关联关系
   */
  relevants?: any
  /**
   * 扩展路径
   */
  extraPaths?: IMenuExtraPath
}

interface IUdMenuState {
  openKeys: string[]
  selectedKeys: string[]
  menuNodes: ReactNode[]
}

export default UdMenu
